package org.thanos.iot.service.role;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.thanos.iot.controller.role.RoleVo;
import org.thanos.iot.entity.role.SysRole;
import org.thanos.iot.entity.role.SysRoleMenu;
import org.thanos.iot.dao.role.SysRoleMapper;
import org.thanos.iot.dao.role.SysRoleMenuMapper;

import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

@Service("roleService")
public class RoleServiceImpl implements RoleService {

    @Autowired
    private SysRoleMapper roleMapper;

    @Autowired
    private SysRoleMenuMapper roleMenuMapper;

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void addRole(String code, List<Integer> menuIds) {
        Assert.isTrue(roleMapper.uniqueCheck(code) == 0, "code is exists");
        SysRole role = new SysRole();
        role.setCode(code);
        Timestamp createTime = Timestamp.valueOf(LocalDateTime.now());
        role.setCreateTime(createTime);
        role.setUpdateTime(createTime);
        roleMapper.insertSelective(role);
        if (!CollectionUtils.isEmpty(menuIds)) {
            List<SysRoleMenu> roleMenus = menuIds.stream().map(menuId -> {
                SysRoleMenu roleMenu = new SysRoleMenu();
                roleMenu.setMenuId(menuId);
                roleMenu.setRoleId(role.getId());
                return roleMenu;
            }).collect(Collectors.toList());
            roleMenuMapper.insertForeach(roleMenus);
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void modifyRole(Integer id, String code, List<Integer> menuIds) {
        SysRole role = roleMapper.selectByPrimaryKey(id);
        Assert.isTrue(Optional.ofNullable(role).isPresent(), "record is not found");
        role.setCode(code);
        role.setUpdateTime(Timestamp.valueOf(LocalDateTime.now()));
        roleMapper.updateByPrimaryKeySelective(role);
        if (!CollectionUtils.isEmpty(menuIds)) {
            roleMenuMapper.deleteByRoleId(id);
            List<SysRoleMenu> roleMenus = menuIds.stream().map(menuId -> {
                SysRoleMenu roleMenu = new SysRoleMenu();
                roleMenu.setMenuId(menuId);
                roleMenu.setRoleId(id);
                return roleMenu;
            }).collect(Collectors.toList());
            roleMenuMapper.insertForeach(roleMenus);
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void deleteRole(Integer roleId) {
        SysRole role = roleMapper.selectByPrimaryKey(roleId);
        Assert.isTrue(Optional.ofNullable(role).isPresent(), "record is not found");
        roleMapper.deleteByPrimaryKey(roleId);
        roleMenuMapper.deleteByRoleId(roleId);
    }

    @Override
    public RoleVo discoverOne(Integer roleId) {
        SysRole role = roleMapper.selectByPrimaryKey(roleId);
        RoleVo roleVo = null;
        if (Optional.ofNullable(role).isPresent()) {
            List<Integer> menus = roleMenuMapper.queryByRoleId(roleId);
            roleVo = new RoleVo();
            roleVo.setId(role.getId());
            roleVo.setCode(role.getCode());
            roleVo.setCreateTime(role.getCreateTime().getTime());
            roleVo.setMenuIds(menus);
        }
        return roleVo;
    }

    @Override
    public List<RoleVo> discoverRoles(String code, Long startTime, Long endTime) {
        Timestamp start = Objects.isNull(startTime) ? null : Timestamp.from(Instant.ofEpochMilli(startTime));
        Timestamp end = Objects.isNull(endTime) ? null : Timestamp.from(Instant.ofEpochMilli(endTime));
        List<SysRole> roles = roleMapper.queryAll(code, start, end);
        if (CollectionUtils.isEmpty(roles)) {
            return Collections.emptyList();
        }
        return roles.stream().map(role -> {
            List<Integer> menus = roleMenuMapper.queryByRoleId(role.getId());
            RoleVo roleVo = new RoleVo();
            roleVo.setId(role.getId());
            roleVo.setCode(role.getCode());
            roleVo.setCreateTime(role.getCreateTime().getTime());
            roleVo.setMenuIds(menus);
            return roleVo;
        }).collect(Collectors.toList());
    }
}
